#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <sys/types.h>   
#include <sys/socket.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/stat.h>
#include <string.h>
#include <getopt.h>
#include <fcntl.h>
#include <net/if.h>
#include <sys/wait.h>

#include <proto.h>
#include "client.h"

#define IPSTRSIZE 40

pid_t pid;
static int chosen_id = 1;
static int rd2;
static void help_message()
{
	printf("请查看手册寻求帮助\n");
}
struct client_conf_st client_conf = 
{
	.rcvport = DEFAULT_RCVPORT,
	.mgroup = DEFAULT_MGROUP,
	.player = DEFAULT_PLAYER
};
static struct option arr[5] = {
	{"port",1,NULL,'P'},
	{"mgroup",1,NULL,'M'},
	{"player",1,NULL,'p'},
	{"help",0,NULL,'H'},
	{NULL,0,NULL,0}
};
static void *sele_chnid(void *arg)
{
	while(1)
	{
	do{
//		printf("\ncurrent channel:%d\n",chosen_id);
//		printf("please input channel you choose:");
		rd2 = scanf("%d",&chosen_id);
//		printf("chosen_id = %d\n",chosen_id);
		if(chosen_id == 0) {
			kill(pid,9);
			wait(NULL);
			exit(0);
		}

	}while(rd2 < 1);
	}
	pthread_exit(NULL);
}

int main(int argc, char *argv[])
{
	pthread_t tid;
	int sd,fd;
	int mark = 1;
	int pd[2];
	int pos = 0;
	int ret;
	int c;
	int option_index = 0;
	struct sockaddr_in laddr,raddr;
	socklen_t raddr_len;
	struct msg_list_st *msg_list;
	struct msg_channel_st *msg_chanel;
	char ipstr[IPSTRSIZE];
	while(1)
	{
		c = getopt_long(argc,argv,"P:M:p:H",arr,&option_index);//这里是四个参数,查看手册
		if(c<0)
		{
			break;
		}
		switch(c)
		{
			case 'P':
				client_conf.rcvport = optarg;
				break;
			case 'M':
				client_conf.mgroup = optarg;
				break;
			case 'p':
				client_conf.player = optarg;
				break;
			case 'H':
				help_message();
				break;
			default:
				abort();
				break;
		}
	}
	sd = socket(AF_INET,SOCK_DGRAM,0/*IPPROTO_UDP*/);
	if(sd < 0)
	{
		perror("socket()");
		exit(1);
	}

	struct ip_mreqn mreq;
    inet_pton(AF_INET,DEFAULT_MGROUP,&mreq.imr_multiaddr);  // 多播组地址MGROUP:224.2.2.2;
    inet_pton(AF_INET,"0.0.0.0",&mreq.imr_address); // 自己的地址
    mreq.imr_ifindex = if_nametoindex(DEFAULT_DEVICES); //索引号

		//   man 7 ip  IPPRORO_IP level; 加入多播组;
	if(setsockopt(sd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq)) < 0)
	{
		perror("setsockopt()");
		exit(1);
	}

	laddr.sin_family = AF_INET;    // bind 绑定套接字;
	laddr.sin_port = htons(atoi(DEFAULT_RCVPORT));
	inet_pton(AF_INET,"0.0.0.0",&laddr.sin_addr);

	if(bind(sd,(void *)&laddr,sizeof(laddr)) < 0)
	{
		perror("bind()");
		exit(1);
	}

	if(pipe(pd) < 0)
	{
		perror("pipe()");
		exit(1);
	}

	pid = fork();
	if(pid < 0)
	{
		perror("fork()");
		exit(1);
	}

	if(pid == 0)
	{
		close(pd[1]);
		dup2(pd[0],0);
		close(pd[0]);

		fd = open("/dev/null",O_RDWR);
		dup2(fd,1);
		dup2(fd,2);
	
		execl("player","player",(char *)0);
		perror("execl()");
		exit(1);
	
	}

	else
	{
		close(pd[0]);
		int rd = 0;
		int rd1 = 0;
		int tid1;
		raddr_len = sizeof(raddr);	/*!!*/
    	msg_list = malloc(MAX_MSG);
		while(1)
		{
			memset(msg_list,'\0',MAX_MSG);
			if((rd = recvfrom(sd,msg_list,MAX_MSG,0,(void *)&raddr,&raddr_len)) < 0)
			{
				perror("recvfrom()");
				exit(1);
			}
			if(mark)
			{
				inet_ntop(AF_INET,&raddr.sin_addr,ipstr,IPSTRSIZE);
				printf("----MESSAGE FROM: %s:%d-----\n",ipstr,ntohs(raddr.sin_port));	
				mark = 0;
			}
			if(ntohl(msg_list->chnid) != CHNID_LIST)
			{
				continue;
			}
			break;
		}

		struct list_entry_st *pos1;

		if(ntohl(msg_list->chnid) == CHNID_LIST)
			for(pos1=&msg_list->entry[0];(char *)pos1<(((char *)(msg_list->entry))+rd-2);pos1=(struct list_entry_st *)((char *)pos1+ntohs(pos1->len)))
			{
				printf("%s",pos1->desc);
			}
		fflush(NULL);
		
		tid1 = pthread_create(&tid,NULL,sele_chnid,NULL);//线程创建
		if (tid1)
		{
			perror("pthread_create()\n");
			exit(1);
		}

		msg_chanel = malloc(MAX_DATA);
		if(msg_chanel == NULL)
		{
			perror("malloc()");
			exit(1);
		}
		
		while(1)
		{
			memset(msg_list,'\0',MAX_DATA);
			rd1 = recvfrom(sd,msg_chanel,MAX_DATA,0,(struct sockaddr *)&raddr,&raddr_len);
			if(ntohs(msg_chanel->chnid) == chosen_id)
			{
				rd1 = rd1 - sizeof(chnid_t);
				pos = 0;
				while(rd1 > 0)
				{
					ret = write(pd[1],msg_chanel->data+pos,rd1);
					if(ret < 0)
					{
						perror("write()");
						exit(1);
					}
					rd1-=ret;
					pos+=ret;
				}
			}
		}
		free(msg_chanel);
	}
	close(pd[1]);
	wait(NULL);
	pthread_exit(NULL);
	close(sd);
	exit(0);
}
